{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 任务返回值设计实现"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 返回值类型Result"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "任务返回值的设计问题\n",
    "\n",
    "- 跨线程获取：任务返回值`Result`需要在不同线程间传递，用户线程提交任务，线程池线程执行任务并产生返回值。\n",
    "- 类型通用性：需要设计能表示任意类型的返回值，类似Java的Object基类或C++17的Any类型。\n",
    "- 线程通信：任务执行完成需要通知用户线程，因此需要信号量机制实现线程间通信。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "返回值类型`Result`的重要性\n",
    "\n",
    "- 开发实践：实际开发中需求文档和架构设计往往只给出框架，具体实现细节需要开发者充分考虑。\n",
    "- 提前设计：在编码前需要仔细考虑类设计，包括属性和行为，避免后期出现难以调试的bug。\n",
    "- 实体抽象：将`Result`看作实体，分析其应包含的属性和行为，如返回值存储和获取机制。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`Result`类的设计思路 \n",
    "\n",
    "- 核心成员：\n",
    "  - `Any`类型成员：存储任务执行结果，可以表示任意数据类型。\n",
    "  - 信号量成员：用于线程间通信，当任务未完成时阻塞用户线程获取结果。\n",
    "- 接口设计：\n",
    "  - `get`方法：用户通过该方法获取结果，若任务未完成则阻塞。\n",
    "  - 类型转换：需要提供将`Any`类型转换为具体类型的方法，如`cast_()`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 任何类型Any"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 设计目的：作为所有类型的基类，可以接收任意数据类型的返回值。\n",
    "- 使用方式：\n",
    "  - 任务类从`Task`继承，重写`run()`方法返回`Any`类型。\n",
    "  - 用户通过`get().cast_()`获取具体类型的返回值。\n",
    "- 实现示例："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "class MyTask : public Task {\n",
    "public:\n",
    "    Any run() {\n",
    "        int sum = 0;\n",
    "        for(int i=begin_; i<=end_; i++) \n",
    "            sum += i;\n",
    "        return sum;  // 自动转换为Any类型\n",
    "    }\n",
    "};"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 信号量Semaphore"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 线程同步：解决任务执行线程和结果获取线程间的同步问题。\n",
    "- 实现原理：\n",
    "  - 当任务未完成时，信号量阻塞用户线程的`get()`调用。\n",
    "  - 任务完成后，信号量通知用户线程可以获取结果。\n",
    "- 设计要点：\n",
    "  - 信号量应作为`Result`类的私有成员。\n",
    "  - 需要合理设计信号量的初始值和等待/通知机制。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `submitTask`函数设计"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 返回值设计：函数返回`Result`对象，用于获取任务执行结果。不能直接返回`Task`对象的`getResult()`，因为`Task`对象在线程执行完后会被析构。\n",
    "- 任务队列控制：使用条件变量`notFull_`控制任务队列上限，提交任务时若队列满则最多等待1秒。\n",
    "- 线程通信机制：任务提交成功后通过`notEmpty_.notify_all()`通知工作线程有新任务可执行。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "前置声明`Task`类型\n",
    "\n",
    "- 对象关系设计：`Result`类需要包含`std::shared_ptr<Task>`成员变量，通过强引用保持`Task`对象存活。\n",
    "- 生命周期管理：使用智能指针确保`Task`对象在`Result`对象存在期间不会被析构。\n",
    "- 前置声明技巧：由于`Task`类定义在`Result`之后，需要使用`class Task;`进行前置声明。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`Result`构造函数 \n",
    "\n",
    "- 有效性标志：增加`std::atomic_bool isValid_`成员，标识任务是否成功提交。\n",
    "- 构造函数重载：提供带`bool`参数的构造函数，用于任务提交失败时创建无效`Result`对象。\n",
    "- 默认析构函数：使用`=default`保留默认析构行为，智能指针成员会自动管理资源释放。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`get`方法实现\n",
    "\n",
    "- 信号量机制：使用`Semaphore sem_`实现线程同步，任务完成时`post`，`get`方法`wait`。\n",
    "- 返回值获取流程：\n",
    "  - 检查`isValid_`标志\n",
    "  - 等待信号量资源\n",
    "  - 返回存储在`Any any_`中的结果\n",
    "- 异常处理：对无效任务直接返回，避免无效等待。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 实际的设计过程\n",
    "\n",
    "- 对象关联设计：采用`Result`包含`Task`的模式而非`Task`包含`Result`，避免`Task`析构导致`Result`失效。\n",
    "- 生命周期考量：\n",
    "  - `Task`对象由线程池线程执行后析构\n",
    "  - `Result`对象由用户代码持有\n",
    "  - 通过`shared_ptr`保持关联\n",
    "- 设计决策要点：\n",
    "  - 任务执行与结果获取分离\n",
    "  - 结果有效性检查机制\n",
    "  - 线程安全的返回值传递"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 任务返回值设计实现二"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## get方法设计"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `Result`类的实现"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "成员变量:\n",
    "\n",
    "- `Any any_`: 存储任务的返回值\n",
    "- `Semaphore sem_`: 线程通信信号量\n",
    "- `std::shared_ptr<Task>task_`: 指向对应获取返回值的任务对象\n",
    "- `std::atomic_bool isValid_`: 返回值是否有效"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`Result`构造函数 \n",
    "\n",
    "实现要点:\n",
    "\n",
    "- 接收`std::shared_ptr<Task>`和`bool isValid`参数\n",
    "- 默认析构函数使用`= default`\n",
    "- 构造时初始化信号量和任务指针"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Any类的实现 \n",
    "\n",
    "- 核心方法:\n",
    "  - `template<typename T> Any(T data)`: 构造函数，可接收任意类型数据\n",
    "  - `template<typename T> T cast_()`: 类型转换方法，使用RTTI进行派生类转换\n",
    "- 注意事项:\n",
    "  - 使用`unique_ptr`管理基类指针，避免直接拷贝\n",
    "  - 类型不匹配时抛出异常"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`setVal`方法设计 \n",
    "\n",
    "- `setVal`方法分析 \n",
    "  - 功能:\n",
    "    - 存储任务返回值到`any_`成员\n",
    "    - 通过信号量通知等待线程\n",
    "  - 实现技巧:\n",
    "    - 使用`std::move`进行资源转移\n",
    "    - 调用`sem_.post()`释放信号量\n",
    "\n",
    "- 任务执行分析 \n",
    "  - 执行流程:\n",
    "    - 线程池从任务队列获取任务\n",
    "    - 执行`task->run()`获取返回值\n",
    "    - 通过`result_->setVal()`设置结果\n",
    "\n",
    "- 思维发散 \n",
    "  - 设计方法:\n",
    "    - 通过封装`exec()`方法扩展功能\n",
    "    - 保持`run()`纯虚函数不变\n",
    "    - 用户只需重写run()方法\n",
    "\n",
    "- 线程池任务执行分析 \n",
    "  - 关键点:\n",
    "    - `exec()`方法中调用`run()`实现多态\n",
    "    - 将返回值通过`result_`指针设置\n",
    "\n",
    "- 功能扩展 \n",
    "  - 扩展技巧:\n",
    "    - 基类提供`exec()`默认实现\n",
    "    - 派生类只需关注业务逻辑\n",
    "    - 避免修改已有虚函数接口\n",
    "\n",
    "- `result`和`task`的关系\n",
    "  - 设计原则:\n",
    "    - `Result`持有`Task`的`shared_ptr`\n",
    "    - `Task`仅持有`Result`的裸指针\n",
    "    - 避免循环引用导致内存泄漏\n",
    "\n",
    "- 增加成员变量 \n",
    "  - 实现细节:\n",
    "    - `Task`类添加`Result* result_`成员\n",
    "    - 提供`setResult()`方法设置指针\n",
    "    - 构造函数初始化指针为`nullptr`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 任务类的实现"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 关键方法:\n",
    "  - `exec()`: 执行任务并设置结果\n",
    "  - `setResult()`: 设置结果对象指针\n",
    "  - `run()`: 纯虚函数，由子类实现\n",
    "- 注意事项:\n",
    "  - 执行前检查`result_`有效性\n",
    "  - 使用裸指针避免循环引用"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 问题总结"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 设计要点:\n",
    "  - 使用信号量实现线程同步\n",
    "  - 通过多态实现任务扩展\n",
    "  - 合理管理对象生命周期\n",
    "- 经验总结:\n",
    "  - 避免智能指针循环引用\n",
    "  - 接口设计要考虑扩展性\n",
    "  - 多积累设计模式应用场景"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 任务返回值设计实现三"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Any类型的设计与实现"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Any类型的设计\n",
    "\n",
    "- 实现原理：使用模板类存储任意类型数据，通过基类指针实现类型擦除\n",
    "- 存储机制：\n",
    "  - 定义`Derive(T data)`模板类继承自基类`Base`\n",
    "  - 使用`std::unique_ptr<Base> base_`保存任意类型数据\n",
    "- 应用场景：解决C++中需要表示任意返回类型的问题，类似Java的Object基类"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "信号量Semaphore实现\n",
    "\n",
    "- 核心功能：实现线程间通信的同步机制\n",
    "- 关键方法：\n",
    "  - `wait()`：减少信号量，资源不足时阻塞线程\n",
    "  - `post()`：增加信号量，唤醒等待线程\n",
    "- 实现要点：需要配合互斥锁使用，保证原子操作"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`Result`机制设计\n",
    "\n",
    "- 核心功能：获取异步任务执行结果\n",
    "- 关键设计：\n",
    "  - 双向关联：与`Task`对象通过`shared_ptr`建立关联\n",
    "  - 线程安全：使用信号量实现结果等待机制\n",
    "  - 类型转换：通过Any类型存储任意返回值\n",
    "- 主要方法：\n",
    "  - `setVal(Any any)`：由`Task`线程调用设置结果值\n",
    "  - `get()`：由用户线程调用获取结果，会阻塞直到结果就绪"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`Task`抽象基类\n",
    "\n",
    "- 核心职责：定义任务执行接口\n",
    "- 关键设计：\n",
    "  - 多态调用：通过虚函数`run()`实现任务具体逻辑\n",
    "  - 结果传递：通过`exec()`方法将`run()`返回值传递给`Result`\n",
    "  - 生命周期：`Task`对象生命周期应长于关联的`Result`对象\n",
    "- 使用模式：用户从`Task`派生具体任务类，实现`run()`方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Master-Slave线程模型\n",
    "\n",
    "- 核心思想：任务分解与结果合并\n",
    "- 三阶段流程：\n",
    "  - 分解阶段：Master线程将大任务分解为子任务\n",
    "  - 执行阶段：Slave线程并行执行子任务\n",
    "  - 合并阶段：Master线程汇总子任务结果\n",
    "- 性能优势：充分利用多核CPU并行计算能力\n",
    "- 实现技巧：\n",
    "  - 使用无符号长整型`uLong`避免大数计算溢出\n",
    "  - 通过线程池管理Slave线程资源"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "实际应用案例\n",
    "\n",
    "- 典型场景：计算1到3亿的累加和\n",
    "- 实现要点：\n",
    "  - 将计算任务分为三个子区间(1-1亿,1亿-2亿,2亿-3亿)\n",
    "  - 使用`submitTask`提交任务到线程池\n",
    "  - 通过`get().cast_<uLong>()`获取计算结果\n",
    "- 验证方法：与单线程计算结果对比确保正确性\n",
    "- 性能考量：多线程执行时间应明显少于单线程"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "设计模式总结\n",
    "\n",
    "- 循环引用处理：`Task`与`Result`之间避免双向智能指针\n",
    "- 类型安全：`Any`类型提供灵活的类型转换机制\n",
    "- 资源管理：\n",
    "  - 使用`unique_ptr`管理专属资源\n",
    "  - 使用`shared_ptr`管理共享资源\n",
    "- 线程安全：信号量+互斥锁保证多线程数据安全"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Catch模式线程池的设计与实现"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "用户设置线程池模式\n",
    "\n",
    "- 模式类型：线程池提供两种工作模式：固定数量线程模式(MODE_FIXED)和动态增长线程模式(MODE_CACHED)\n",
    "- 设置方法：通过调用`setMode`方法设置工作模式，例如设置为CATCH模式\n",
    "- 设置时机：在调用`start()`方法启动线程池之前设置模式"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "用户提交任务时判断是否需要创建新线程\n",
    "\n",
    "- 任务队列检查：提交任务时先检查任务队列是否已满，若满则等待最多1秒\n",
    "- 动态线程创建：在CATCH模式下，当任务数量多而线程少时，需要动态创建新线程\n",
    "- 判断条件：根据任务数量和空闲线程数量判断是否需要创建新线程\n",
    "- 线程创建方式：使用智能指针和绑定器创建新线程对象\n",
    "- 任务获取机制：线程通过获取锁后从任务队列取任务，使用条件变量`notEmpty`等待任务\n",
    "- 任务通知机制：当有新任务放入队列时，通过`notify_all`通知所有等待线程"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程回收\n",
    "\n",
    "- 空闲时间控制：在CATCH模式下，线程空闲超过60秒应被回收\n",
    "- 线程回收原因：线程数量并非越多越好，过多线程会浪费资源\n",
    "- 回收实现：需要计算线程空闲时间，超过阈值时结束并回收线程"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "问题总结 \n",
    "\n",
    "- 三个核心问题：\n",
    "  - 如何设置线程池工作模式\n",
    "  - 如何根据任务和线程数量动态创建线程\n",
    "  - 如何控制并回收空闲超时的线程\n",
    "- 设计要点：\n",
    "  - 使用智能指针管理线程对象\n",
    "  - 通过条件变量实现线程间通信\n",
    "  - 合理设置任务队列阈值和线程空闲时间阈值"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "C++17",
   "language": "C++17",
   "name": "xcpp17"
  },
  "language_info": {
   "name": "C++17"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
